package com.fast.orm.utils;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.NumberUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.fast.orm.many.AutoQueryInfo;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.BiConsumer;
import java.util.function.Function;

public class BeanConvertUtil {

    public static void joinMerge(List<JSONObject> thisJson, List<JSONObject> targetJson, AutoQueryInfo autoQueryInfo) {
        if (CollUtil.isEmpty(thisJson)||CollUtil.isEmpty(targetJson)) {
            return;
        }
        Map<Object, List<JSONObject>> thisResultGroupMap = new HashMap<>();
        for (JSONObject data : thisJson) {
            Object temp = data.get(autoQueryInfo.getTargetColumnName());
            if (temp == null) {
                continue;
            }
            Object value = NumberUtil.isNumber(temp.toString()) ? NumberUtil.parseNumber(temp.toString()) : temp;
            List<JSONObject> joinResultGroupList = thisResultGroupMap.get(value);
            if (joinResultGroupList == null) {
                joinResultGroupList = new ArrayList<>();
                thisResultGroupMap.put(value, joinResultGroupList);
            }
            joinResultGroupList.add(data);
        }

        Map<Object, List<JSONObject>> targetResultGroupMap = new HashMap<>();
        for (JSONObject data : targetJson) {
            Object temp = data.get(autoQueryInfo.getThisColumnName());
            if (temp == null){
                continue;
            }
            Object value = NumberUtil.isNumber(temp.toString()) ? NumberUtil.parseNumber(temp.toString()) : temp;
            List<JSONObject> joinResultGroupList = targetResultGroupMap.get(value);
            if (joinResultGroupList == null) {
                joinResultGroupList = new ArrayList<>();
                targetResultGroupMap.put(value, joinResultGroupList);
            }
            joinResultGroupList.add(data);
        }
        for (Object resultDataGroupKey : thisResultGroupMap.keySet()) {
            List<JSONObject> joinDataGroupList = targetResultGroupMap.get(resultDataGroupKey);
            if (CollUtil.isNotEmpty(joinDataGroupList)) {
                for (JSONObject resultData : thisResultGroupMap.get(resultDataGroupKey)) {
                    if (autoQueryInfo.getCollectionType()) {
                        resultData.put(autoQueryInfo.getFieldName(),joinDataGroupList);
                    }else {
                        if (autoQueryInfo.getBasicType()) {
                            resultData.put(autoQueryInfo.getFieldName(),joinDataGroupList.get(0).get(autoQueryInfo.getValueColumnName()));
                        }else {
                            resultData.put(autoQueryInfo.getFieldName(),JSONObject.parseObject(joinDataGroupList.get(0).toString()));
                        }
                    }
                }
            }
        }
    }


    public static <T, U> Map<U, T> toMap(List<T> list, Function<? super T, ? extends U> valueMapper) {
        if (CollUtil.isEmpty(list)) {
            return null;
        }
        Map<U, T> map = new HashMap<>();
        for (T t : list) {
            map.put(valueMapper.apply(t), t);
        }
        return map;
    }

    public static <T, U> Map<U, List<T>> toMapGroup(List<T> list, Function<? super T, ? extends U> valueMapper) {
        if (CollUtil.isEmpty(list)) {
            return null;
        }
        Map<U, List<T>> map = new HashMap<>();
        for (T t : list) {
            U key = valueMapper.apply(t);
            List<T> vs = map.get(key);
            if (CollUtil.isEmpty(vs)) {
                vs = new ArrayList<>();
                map.put(key, vs);
            }
            vs.add(t);
        }
        return map;
    }

    public static <T1, T2, K> void merge(List<T1> l1, Function<T1, K> k1, List<T2> l2, Function<T2, K> k2, BiConsumer<T1, T2> s1) {
        for (T1 t1 : l1) {
            K v1 = k1.apply(t1);
            for (T2 t2 : l2) {
                K v2 = k2.apply(t2);
                if (v1.equals(v2)) {
                    s1.accept(t1, t2);
                    continue;
                }
            }
        }
    }

    public static <T1, T2, K> void mergeList(List<T1> l1, Function<T1, K> k1, List<T2> l2, Function<T2, K> k2, BiConsumer<T1, List<T2>> s1) {
        for (T1 t1 : l1) {
            K v1 = k1.apply(t1);
            List<T2> ts2 = new ArrayList<>();
            for (T2 t2 : l2) {
                K v2 = k2.apply(t2);
                if (v1.equals(v2)) {
                    ts2.add(t2);
                }
            }
            s1.accept(t1, ts2);
        }
    }


}
